package org.teremail.mailbox;

import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.teremail.mailbox.Path.path;

import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public abstract class AbstractCacheMailboxDAOTestCase {

    MailboxDAO mockDao;
    MailboxDAO dao;
    
    @Before
    public void setup() {
        mockDao = EasyMock.createMock(MailboxDAO.class);        
        dao = getCachedMailboxDAO(mockDao);
    }
    
    protected abstract MailboxDAO getCachedMailboxDAO(MailboxDAO mockDao);
    
    @Test
    public void createMailbox() throws Exception {
        
        String name = "bart";
        
        expect(mockDao.create(name)).andReturn(new MailboxDO("123", name));
        
        replay(mockDao);
        
        dao.create(name);
        MailboxDO mdo = dao.findMailbox(name);
        assertEquals(name, mdo.getUser());
        
        verify(mockDao);
    }
    
    @Test
    public void findMailboxTwice() throws Exception {
        
        String name = "bart";
        
        expect(mockDao.findMailbox(name)).andReturn(new MailboxDO("123", name));
        
        replay(mockDao);
        
        MailboxDO mdo = dao.findMailbox(name);
        mdo = dao.findMailbox(name);
        assertEquals(name, mdo.getUser());
        
        verify(mockDao);
    }
    
    @Test
    public void createFolder() throws Exception {
        
        String name = "bart";        
        MailboxDO mdo = new MailboxDO("123", name);
        FolderDO fdo = new FolderDO(Path.INBOX, mdo);
        
        expect(mockDao.save(fdo)).andReturn(new FolderDO("456", fdo));
        
        replay(mockDao);
        
        FolderDO saved = dao.save(fdo);
        assertNotNull(saved.getId());
        FolderDO found = dao.findFolder(mdo, Path.INBOX);
        assertEquals(saved.getId(), found.getId());
        
        verify(mockDao);
        
    }
    
    @Test
    public void findFolderTwice() throws Exception {
        
        MailboxDO mdo = new MailboxDO("123", "homer");
        FolderDO fdo = new FolderDO(Path.INBOX, mdo);
        
        expect(mockDao.findFolder(mdo, Path.INBOX)).andReturn(fdo);
        
        replay(mockDao);
        
        dao.findFolder(mdo, Path.INBOX);
        dao.findFolder(mdo, Path.INBOX);
        
        verify(mockDao);
        
    }
    
    @Test(expected = FolderNotExistsException.class)
    public void removeFolder() throws Exception {
        MailboxDO mdo = new MailboxDO("123", "homer");
        Path oldPath = path("OldFolder");
        FolderDO fdo = new FolderDO(oldPath, mdo);
        
        expect(mockDao.save(fdo)).andReturn(new FolderDO("123", fdo));
        mockDao.remove(fdo.getMailbox(), fdo.getPath());
        expect(mockDao.findFolder(mdo, oldPath)).andThrow(new FolderNotExistsException(mdo.getUser(), oldPath.toString()));
        
        replay(mockDao);
        
        dao.save(fdo);
        dao.remove(mdo, oldPath);
        dao.findFolder(mdo, oldPath);
        
        verify(mockDao);
    }
    
    @Test(expected = FolderNotExistsException.class)
    public void renameFolder() throws Exception {
        MailboxDO mdo = new MailboxDO("123", "homer");
        Path oldPath = path("OldFolder");
        Path newPath = path("NewFolder");
        FolderDO fdo = new FolderDO(oldPath, mdo);
        
        expect(mockDao.save(fdo)).andReturn(new FolderDO("123", fdo));
        mockDao.renameFolder(fdo.getMailbox(), fdo.getPath(), newPath);
        expect(mockDao.findFolder(mdo, oldPath)).andThrow(new FolderNotExistsException(mdo.getUser(), oldPath.toString()));
        
        replay(mockDao);
        
        dao.save(fdo);
        dao.renameFolder(mdo, oldPath, newPath);
        dao.findFolder(mdo, oldPath);
        
        verify(mockDao);
    }
}
